// ThreadCache 层结构封装分析
#include "common.hpp"
#include "centralCache.hpp"

class ThreadCache
{
private:
    FreeList thread_freelist_array[ThreadCache_FreeLists];  // ThreadCache 层共 208 个自由链表
public:
    // 先判断 ThreadCache 层是否有足够的空间供我们使用，若足够则直接从自由链表中拿去，若不够则 肯定会向 CentralCache 中申请空间，并且也会 往CentralCache 中释放内存块空间
    void* allocateMem(size_t bytes) // 要申请的空间字节大小
    {
        assert(bytes <= ThreadCache_Max_Bytes);
        size_t alignSize = ObjFreelist_AlignMap::roundUp(bytes);    // 对齐后的总字节大小
        size_t index = ObjFreelist_AlignMap::hashIndex(bytes);
        // 若申请的空间对象 自由链表中足够，则直接拿
        if(!thread_freelist_array[index].isEmptyList()){
            return thread_freelist_array[index].popObjFromList();
        }
        else{   // 不够，往 CentralCache 中申请
            return FetchFromCentralCache(index, alignSize);
        }
    }
    // 释放内存对象到 CentralCache
    void deallocateMem(void* ptr, size_t bytes)
    {
        assert(ptr);
        assert(bytes <= ThreadCache_Max_Bytes);
        // 1.找出对应的自由链表桶将对象插入
        size_t index = ObjFreelist_AlignMap::hashIndex(bytes);
        thread_freelist_array[index].pushObjToList(ptr);
        // 2.当自由链表的长度 大于 一次性批量申请的对象个数时 就开始还一段list 给 CentralCache
        if(thread_freelist_array[index].getObjNum() >= thread_freelist_array[index].getMaxObj()){
           listTooLong(thread_freelist_array[index], bytes);
        }
    }

    // 从 CentralCache 中心缓存中获取对象
    void* FetchFromCentralCache(size_t index, size_t alignSize);
    // 链表太长，将一部分对象还给 CentralCache
    void listTooLong(FreeList& freelist, size_t bytes);
};

// threadcache TLS 的无锁访问（Windows特有的）
static _declspec(thread) ThreadCache* pTLSThreadCache = nullptr;


// 从 CentralCache 中心缓存中获取对象
void* ThreadCache::FetchFromCentralCache(size_t index, size_t alignSize)
{
    // 1, 慢反馈调节算法
    //     a.刚开始时不会一次性向 CentralCache 一批量要太多，因为要太多了可能会用不完
    //     b.如果不断有 size 大小的内存需求，那么 objNum 就会不断增长，直到上限512
    size_t objNum = std::min(thread_freelist_array[index].getMaxObj(), ObjFreelist_AlignMap::getMaxObjFromCentralCache(alignSize));
    if(objNum == thread_freelist_array[index].getMaxObj()){
        thread_freelist_array[index].getMaxObj() += 1;
    }
    // 2.开始申请获取对象
    void* start = nullptr;
    void* end = nullptr;
    size_t actualNum = CentralCache::getInstance()->t_fetchRangeObj(start, end, objNum, alignSize);
    assert(actualNum >= 1);

    // 3.根据申请对象的数量和需要的对象数量，进行不同的代码
    if(actualNum == 1){     // 申请到的对象是 1 个，则直接返回给 用户 即可
        assert(start == end);
        return start;
    }
    // 申请到的对象是多个，则需要将剩下的对象 挂到对应的 threadCache 的自由链表中
    thread_freelist_array[index].pushRangeObj(Util::nextObj(start), end, actualNum - 1);
    return start;
}

void ThreadCache::listTooLong(FreeList& freelist, size_t bytes)
{
    void* start = nullptr;
    void* end = nullptr;
    // 1.从freelist 中取出一批量个数的对象
    freelist.popRangeObj(start, end, freelist.getMaxObj());
    // 2. 将取出的对象还给 CentralCache 的对应的 Span 中
    CentralCache::getInstance()->t_retRangeObjToCentralCache(start, bytes);
    
}